package com.gln.bloger.dao.impl;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.HibernateCallback;

import com.gln.bloger.constant.Constant;
import com.gln.bloger.dao.EntryDao;
import com.gln.bloger.exception.BlogerException;
import com.gln.bloger.pojos.Category;
import com.gln.bloger.pojos.Entry;
import com.gln.bloger.pojos.Tag;
import com.gln.bloger.pojos.Website;
import com.gln.bloger.util.DateUtil;

public class EntryDaoImpl extends BaseDaoImpl<Entry> implements EntryDao{
	/**
	 * for guest
	 */
	@SuppressWarnings("unchecked")
	public List<Entry> getEntries(Website website)
			throws BlogerException {
		DetachedCriteria criteria = DetachedCriteria.forClass(Entry.class);
		criteria.add(Restrictions.eq("website", website));
		criteria.add(Restrictions.eq("status",Constant.ENTRY_SAVETYPE_PUBLISH));
		criteria.addOrder(Order.desc("dateCreated"));
		return getHibernateTemplate().findByCriteria(criteria);
	}

	/**
	 *for guest by category 
	 */
	@SuppressWarnings("unchecked")
	public List<Entry> getEntries(Website website, Category category)
			throws BlogerException {
		DetachedCriteria criteria = DetachedCriteria.forClass(Entry.class);
		criteria.add(Restrictions.eq("website", website));
		criteria.add(Restrictions.eq("category", category));
		criteria.add(Restrictions.eq("status",Constant.ENTRY_SAVETYPE_PUBLISH));
		criteria.addOrder(Order.desc("dateCreated"));
		return getHibernateTemplate().findByCriteria(criteria);
	}

	/**
	 * for guest
	 */
	@SuppressWarnings("unchecked")
	public List<Entry> getRecentEntries(Website website, int size) throws BlogerException {
		DetachedCriteria criteria = DetachedCriteria.forClass(Entry.class);
		criteria.add(Restrictions.eq("website", website));
		criteria.add(Restrictions.eq("status",Constant.ENTRY_SAVETYPE_PUBLISH));
		criteria.addOrder(Order.desc("dateCreated"));
		return getHibernateTemplate().findByCriteria(criteria, -1, size);
	}

	/**
	 * get all entries for author
	 */
	@SuppressWarnings("unchecked")
	public List<Entry> getAllEntries(Website website) throws BlogerException {
		DetachedCriteria criteria = DetachedCriteria.forClass(Entry.class);
		criteria.add(Restrictions.eq("website", website));
		criteria.addOrder(Order.desc("dateCreated"));
		return getHibernateTemplate().findByCriteria(criteria);
	}

	@SuppressWarnings("unchecked")
	public List<Entry> getEntries(Website website, String tagId)
			throws BlogerException {
		DetachedCriteria criteria = DetachedCriteria.forClass(Entry.class);
		DetachedCriteria tagCriteria = criteria.createAlias("tags", "t");
		tagCriteria.add(Restrictions.eq("t.id", tagId));
		criteria.add(Restrictions.eq("website", website));
		criteria.add(Restrictions.eq("status",Constant.ENTRY_SAVETYPE_PUBLISH));
		criteria.addOrder(Order.desc("dateCreated"));
		return getHibernateTemplate().findByCriteria(criteria);
	}

	@SuppressWarnings("unchecked")
	public Entry getNextEntry(final Website website, final String id)
			throws BlogerException {
		List<Entry> entries = getHibernateTemplate().executeFind(new HibernateCallback(){
			public Object doInHibernate(Session session) throws HibernateException, SQLException {
				Query query = session.createQuery("from Entry entry where entry.dateCreated > " +
						"(select current.dateCreated from Entry current where current.id=:id) " +
						"and entry.status=:status and entry.website=:website order by entry.dateCreated asc");
				query.setParameter("id", id);
				query.setParameter("status", Constant.ENTRY_SAVETYPE_PUBLISH);
				query.setParameter("website", website);
				query.setMaxResults(1);
				return query.list();
			}});
		if(entries.isEmpty())
			return null;
		else
			return entries.get(0);
	}

	@SuppressWarnings("unchecked")
	public Entry getPreviousEntry(final Website website, final String id)
			throws BlogerException {
		List<Entry> entries = getHibernateTemplate().executeFind(new HibernateCallback(){
			public Object doInHibernate(Session session) throws HibernateException, SQLException {
				Query query = session.createQuery("from Entry entry where entry.dateCreated < " +
						"(select current.dateCreated from Entry current where current.id=:id) " +
						"and entry.status=:status and entry.website=:website order by entry.dateCreated desc");
				query.setParameter("id", id);
				query.setParameter("status", Constant.ENTRY_SAVETYPE_PUBLISH);
				query.setParameter("website", website);
				query.setMaxResults(1);
				return query.list();
			}});
		if(entries.isEmpty())
			return null;
		else
			return entries.get(0);
	}

	@SuppressWarnings("unchecked")
	public List<Entry> getRelatedEntries(Website website, Entry entry, int size)
			throws BlogerException {
		List<String> ids = new ArrayList<String>();
		for(Tag tag:entry.getTags()) {
			ids.add(tag.getId());
		}
		if(ids.isEmpty()) {
			return new ArrayList<Entry>();
		}
		DetachedCriteria criteria = DetachedCriteria.forClass(Entry.class);
		criteria.add(Restrictions.not(Restrictions.eq("id", entry.getId())));
		criteria.addOrder(Order.desc("dateCreated"));
		criteria.add(Restrictions.eq("status", Constant.ENTRY_SAVETYPE_PUBLISH));
		criteria.add(Restrictions.eq("website", website));
		criteria.setResultTransformer(DetachedCriteria.DISTINCT_ROOT_ENTITY);
		criteria.createCriteria("tags").add(Restrictions.in("id", ids));
		List<Entry> result = getHibernateTemplate().findByCriteria(criteria, -1, size);
		return result;
	}

	@SuppressWarnings("unchecked")
	public List<Entry> getEntriesByMonth(Website website, Date month)
			throws BlogerException {
		DetachedCriteria criteria = DetachedCriteria.forClass(Entry.class);
		criteria.add(Restrictions.between("dateCreated", 
				     DateUtil.getMinDateOfMonth(month), 
				     DateUtil.getMaxDateOfMonth(month)));
		criteria.add(Restrictions.eq("status", Constant.ENTRY_SAVETYPE_PUBLISH));
		criteria.add(Restrictions.eq("website", website));
		List<Entry> result = getHibernateTemplate().findByCriteria(criteria);
		return result;
	}

	@SuppressWarnings("unchecked")
	public List<Date> getArchivedMonthList(Website website)
			throws BlogerException {
		DetachedCriteria criteria = DetachedCriteria.forClass(Entry.class);
		criteria.add(Restrictions.eq("website", website));
		criteria.add(Restrictions.eq("status",Constant.ENTRY_SAVETYPE_PUBLISH));
		/**
		 * only fetch the dateCreated property
		 */
		criteria.setProjection(Projections.distinct(Projections.property("dateCreated")));
		criteria.addOrder(Order.desc("dateCreated"));
		List<Date> monthList = getHibernateTemplate().findByCriteria(criteria);
		List<Date> result = new ArrayList<Date>();
		for(Date date : monthList){
			Date tmp = DateUtil.getMinDateOfMonth(date);
			if(!result.contains(tmp))
			result.add(tmp);
		}
		return result;
	}
}
